home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Python 1.4 / Python 1.4 source / Mac / GUSI-mods / GUSIDispatch.cp < prev    next >
Encoding:
Text File  |  1996-10-17  |  28.0 KB  |  1,388 lines  |  [TEXT/CWIE]

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIDispatch.cp-    Dispatch calls to their correct recipient
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C/C++
  6.  
  7. $Log: GUSIDispatch.cp,v $
  8. Revision 1.4  1994/12/30  19:48:09  neeri
  9. Remove (theoretical) support for pre-System 6 systems.
  10. Remove built-in support for INETd.
  11. Fix problems in connection with ROM PowerPC library.
  12. Move open() to GUSIFileDispatch.cp.
  13. Support AF_UNSPEC domains.
  14. More work on spinning performance.
  15.  
  16. Revision 1.3  1994/08/10  00:30:30  neeri
  17. Sanitized for universal headers.
  18. Prevent overly fast spinning.
  19.  
  20. Revision 1.2  1994/05/01  23:47:34  neeri
  21. Extend fflush() kludge.
  22. Define _lastbuf for MPW 3.2 compatibility.
  23.  
  24. Revision 1.1  1994/02/25  02:28:36  neeri
  25. Initial revision
  26.  
  27. Revision 0.27  1993/11/24  00:00:00  neeri
  28. Flush stdio before closing
  29.  
  30. Revision 0.26  1993/11/22  00:00:00  neeri
  31. Extend two time loser for EBADF
  32.  
  33. Revision 0.25  1993/11/12  00:00:00  neeri
  34. Two time loser workaround for flush bug
  35.  
  36. Revision 0.24  1993/06/27  00:00:00  neeri
  37. {pre,post}_select
  38.  
  39. Revision 0.23  1993/06/27  00:00:00  neeri
  40. ftruncate
  41.  
  42. Revision 0.22  1993/06/20  00:00:00  neeri
  43. Further subtleties in console handling 
  44.  
  45. Revision 0.21  1993/05/21  00:00:00  neeri
  46. Suffixes
  47.  
  48. Revision 0.20  1993/05/15  00:00:00  neeri
  49. Try to keep errno always set on error returns
  50.  
  51. Revision 0.19  1993/05/13  00:00:00  neeri
  52. Limit Search for configuration resource to application
  53.  
  54. Revision 0.18  1993/01/31  00:00:00  neeri
  55. Introducing daemons (pleased to meet you, hope you guess my name)
  56.  
  57. Revision 0.17  1993/01/17  00:00:00  neeri
  58. Be more careful about user aborts.
  59.  
  60. Revision 0.16  1993/01/03  00:00:00  neeri
  61. GUSIConfiguration
  62.  
  63. Revision 0.15  1992/11/25  00:00:00  neeri
  64. Still trying to get standard descriptors for standalone programs right. sigh.
  65.  
  66. Revision 0.14  1992/10/05  00:00:00  neeri
  67. Small fix in event dispatching
  68.  
  69. Revision 0.13  1992/09/12  00:00:00  neeri
  70. getdtablesize()
  71.  
  72. Revision 0.12  1992/08/30  00:00:00  neeri
  73. Move hasPPC to GUSIPPC.cp, AppleTalkIdentity
  74.  
  75. Revision 0.11  1992/08/05  00:00:00  neeri
  76. Change the way standard I/O channels are opened
  77.  
  78. Revision 0.10  1992/08/03  00:00:00  neeri
  79. Move Scatter/Gather to GUSIBuffer.cp
  80.  
  81. Revision 0.9  1992/07/30  00:00:00  neeri
  82. Features with initializers
  83.  
  84. Revision 0.8  1992/07/13  00:00:00  neeri
  85. hasProcessMgr
  86.  
  87. Revision 0.7  1992/06/27  00:00:00  neeri
  88. choose(), hasNewSF
  89.  
  90. Revision 0.6  1992/06/06  00:00:00  neeri
  91. Feature
  92.  
  93. Revision 0.5  1992/04/19  00:00:00  neeri
  94. C++ Rewrite
  95.  
  96. Revision 0.4  1992/04/18  00:00:00  neeri
  97. Changed read/write/send/recv dispatchers
  98.  
  99. Revision 0.3  1992/04/17  00:00:00  neeri
  100. Spin routines
  101.  
  102. Revision 0.2  1992/04/16  00:00:00  neeri
  103. User interrupt stuff
  104.  
  105. Revision 0.1  1992/03/31  00:00:00  neeri
  106. unix domain socket calls
  107.  
  108. *********************************************************************/
  109.  
  110. #include "GUSIFile_P.h"
  111. #include "GUSIMPW_P.h"
  112. #include <SetJmp.h>
  113. #include <Signal.h>
  114. #include <CursorCtl.h>
  115. #include <Resources.h>
  116. #include <Events.h> 
  117. #include <Windows.h>
  118. #include <Desk.h>
  119. #include <Script.h>
  120. #include <OSEvents.h>
  121. #include <Traps.h>
  122. #include <CommResources.h>
  123. #include <CTBUtilities.h>
  124. #include <Connections.h>
  125. #include <FileTransfers.h>
  126. #include <Terminals.h>
  127. #include <EPPC.h>
  128. #include <PLStringFuncs.h>
  129. #include <LowMem.h>
  130. #include <Processes.h>
  131.  
  132. #if GENERATINGCFM
  133. #include <FragLoad.h>
  134. #endif
  135.  
  136. #pragma segment GUSI
  137.  
  138. /***************************** Globals ******************************/
  139.  
  140. GUSIConfiguration GUSIConfig;            // Change the order of these declarations
  141. SocketTable                    Sockets;            //     and you'll regret it (ARM §12.6.1)
  142. GUSISpinFn                     GUSISpin     = GUSIDefaultSpin;
  143. GUSIExecFn                    GUSIExec        = GUSIDefaultExec;
  144. static GUSIEvtHandler *    evtHandler    = nil;
  145. static short                evtMask        = 0;
  146. static int                    errorSock    = -1;
  147. static int                    errorType    = 0;
  148. static int                    errorCount    = 0;
  149. const int                    errorMax        = 3;
  150. Boolean                        CatchStdIO    = false;
  151.  
  152. Feature     hasMakeFSSpec(
  153.                 gestaltFSAttr,
  154.                 (1<<gestaltHasFSSpecCalls),
  155.                 (1<<gestaltHasFSSpecCalls));
  156. Feature     hasAlias(
  157.                 gestaltAliasMgrAttr,
  158.                 (1<<gestaltAliasMgrPresent),
  159.                 (1<<gestaltAliasMgrPresent));
  160. Feature    hasNewSF(
  161.                 gestaltStandardFileAttr,
  162.                 (1<<gestaltStandardFile58),
  163.                 (1<<gestaltStandardFile58));
  164. Feature     hasProcessMgr(
  165.                 gestaltOSAttr,
  166.                 (1<<gestaltLaunchControl),
  167.                 (1<<gestaltLaunchControl));
  168. Feature hasCRM_P(
  169.                 gestaltCRMAttr,
  170.                 (1<<gestaltCRMPresent),
  171.                 (1<<gestaltCRMPresent));
  172. Feature hasCRM(hasCRM_P, InitCRM);
  173. Feature hasCTB(hasCRM, InitCTBUtilities);
  174. Feature hasStdNBP_P(
  175.                 gestaltStdNBPAttr,
  176.                 (1<<gestaltStdNBPPresent),
  177.                 (1<<gestaltStdNBPPresent));
  178. Feature hasStdNBP(hasCTB, hasStdNBP_P);
  179. Feature hasAppleEvents(
  180.                 gestaltAppleEventsAttr,
  181.                 (1<<gestaltAppleEventsPresent),
  182.                 (1<<gestaltAppleEventsPresent));
  183. Feature hasRevisedTimeMgr(
  184.             gestaltTimeMgrVersion,
  185.             2L);
  186.  
  187. /*********************** Error propagation ************************/
  188.  
  189. #ifdef GUSI_DISPATCH
  190. inline
  191. #endif
  192. int GUSI_error(int err)
  193. {
  194.     errno =    err;
  195.  
  196.     return -1;
  197. }
  198.  
  199. #ifdef GUSI_DISPATCH
  200. inline
  201. #endif
  202. void * GUSI_error_nil(int err)
  203. {
  204.     errno =    err;
  205.  
  206.     return nil;
  207. }
  208.  
  209. /*********************** GUSIConfiguration members ************************/
  210.  
  211. #ifndef GUSI_DISPATCH
  212.  
  213. Boolean     GUSIConfiguration::firstTime = false;
  214. short        GUSIConfiguration::we;
  215.  
  216. void GUSIConfiguration::GUSILoadConfiguration(Handle h)
  217. {
  218.     typedef GUSIConfigRsrc **    GUSIConfHdl;
  219.     GUSIConfHdl config    =    GUSIConfHdl(h);
  220.     long            confSize    =    config ? GetHandleSize(Handle(config)) : 0;
  221.     
  222.     if (confSize < 4 || !(defaultType = (*config)->defaultType))
  223.         defaultType    =    'TEXT';
  224.     if (confSize < 8 || !(defaultCreator = (*config)->defaultCreator))
  225.         defaultCreator    =    'MPS ';
  226.     if (confSize < 9) 
  227.         autoSpin    =    1;            // do automatic spin on read/write
  228.     else
  229.         autoSpin = (*config)->autoSpin;
  230.             
  231.     if (confSize < 14)
  232.         version = '0102';
  233.     else
  234.         version = (*config)->version;
  235.  
  236.     if (confSize < 10) {
  237.         noChdir            =    false;    // Use chdir()
  238.         accurStat        =    false;    // st_nlink = # of entries + 2
  239.         hasConsole        =    false;
  240.         noAutoInitGraf    =     false;
  241.         sharedOpen        =    false;
  242.         sigPipe            =    false;
  243.         delayConsole        =    false;
  244.     } else {
  245.         noChdir            =    ((*config)->flags & 0x80) != 0;
  246.         accurStat        =    ((*config)->flags & 0x40) != 0;
  247.         hasConsole        =    version >= '0150' && ((*config)->flags & 0x08) != 0;
  248.         noAutoInitGraf    =    version >= '0174' && ((*config)->flags & 0x04) != 0;
  249.         sharedOpen        =    version >= '0174' && ((*config)->flags & 0x02) != 0;
  250.         sigPipe            =    version >= '0174' && ((*config)->flags & 0x01) != 0;
  251.         delayConsole        =    false;    /* For now */
  252.     }
  253.     
  254.     if (version < '0120' || confSize < 16)
  255.         numSuffices = 0;
  256.     else
  257.         numSuffices = (*config)->numSuffices;
  258.     
  259.     if (!numSuffices)
  260.         suffices = nil;
  261.     else if (suffices = new GUSISuffix[numSuffices]) {
  262.         memcpy(suffices, (*config)->suffices, numSuffices*sizeof(GUSISuffix));
  263.         for (int i=0; i<numSuffices; i++)
  264.             for (int j=0; j<4; j++)
  265.                 if (((char *) (suffices+i))[j] == ' ')
  266.                     ((char *) (suffices+i))[j] = 0;
  267.     }
  268. }
  269.  
  270. GUSIConfiguration::GUSIConfiguration()
  271. {
  272.     short    oldResFile = CurResFile();
  273.     
  274.     if (!firstTime)
  275.         we = oldResFile;
  276.     else
  277.         UseResFile(we);
  278.         
  279.     Handle config     =    Get1Resource('GU·I', GUSIRsrcID);
  280.     GUSILoadConfiguration(config);    
  281.     if (!firstTime) {
  282.         firstTime    =    true;
  283.         
  284.         if (!noChdir)
  285.             chdir(":");
  286.     } else
  287.         UseResFile(oldResFile);
  288. }
  289.  
  290. void GUSIConfiguration::SetDefaultFType(const TFileSpec & name) const
  291. {
  292.     FInfo    info;    
  293.  
  294.     if (HGetFInfo(name.vRefNum, name.parID, name.name, &info))
  295.         return;
  296.  
  297.     Ptr dot = PLstrrchr(name.name, '.');
  298.     
  299.     if (dot && (name.name[0] - (dot-Ptr(name.name))) <= 4) {
  300.         char searchsuffix[5];
  301.         
  302.         strncpy(searchsuffix, dot+1, name.name[0] - (dot-Ptr(name.name)));
  303.         
  304.         for (int i = 0; i<numSuffices; i++)
  305.             if (!strncmp(suffices[i].suffix, searchsuffix, 4)) {
  306.                 info.fdType     =    suffices[i].suffType;
  307.                 info.fdCreator    =    suffices[i].suffCreator;
  308.                 
  309.                 goto determined;
  310.             }
  311.     }
  312.  
  313.     info.fdType     =    defaultType;
  314.     info.fdCreator    =    defaultCreator;
  315.  
  316. determined:    
  317.     HSetFInfo(name.vRefNum, name.parID, name.name, &info);
  318. }
  319.  
  320. void GUSIConfiguration::DoAutoInitGraf() const
  321. {
  322.     if (*(GrafPtr **) LMGetCurrentA5() != &qd.thePort)
  323.         InitGraf(&qd.thePort);
  324.     const_cast<GUSIConfiguration *>(this)->noAutoInitGraf    =    true;
  325. }
  326.  
  327. #endif // GUSI_DISPATCH
  328.  
  329. inline void GUSIConfiguration::DoAutoSpin() const 
  330. {
  331.     if (autoSpin)
  332.         SAFESPIN(0, SP_AUTO_SPIN, autoSpin);
  333. }
  334.  
  335. Boolean GUSIConfiguration::DelayConsole() const
  336. {
  337.     return delayConsole;
  338. }
  339.  
  340. /************************ Handle nonstandard consoles *************************/
  341.  
  342. #ifndef GUSI_DISPATCH
  343.  
  344. static void InitConsole()
  345. {
  346.     if (MPWDomain::stdopen) {
  347.         for (int i = 0; i < 3; i++) {
  348.             Socket * sock =     MPWDomain::stdopen(i);
  349.  
  350.             if (sock)
  351.                 Sockets.Install(sock);
  352.         }
  353.     } else {
  354.         if (open("dev:console", O_RDONLY) < 0)
  355.             open("dev:null", O_RDONLY);
  356.         if (open("dev:console", O_WRONLY) < 0)
  357.             open("dev:null", O_WRONLY);
  358.         if (open("dev:console", O_WRONLY) < 0)
  359.             open("dev:null", O_WRONLY); 
  360.     }
  361. }
  362.  
  363. void SocketTable::InitConsole()
  364. {
  365.     if (needsConsole) {
  366.         needsConsole = false;
  367.         ::InitConsole();
  368.     }
  369. }
  370.  
  371. #endif // GUSI_DISPATCH
  372.  
  373. /************************ External routines *************************/
  374.  
  375. int getdtablesize()
  376. {
  377.     return GUSI_MAX_FD;
  378. }
  379.  
  380. int socket(int domain, int type, int protocol)
  381. {
  382.     SocketDomain *    dom;
  383.     Socket *         sock;
  384.     int                fd;
  385.  
  386.     Sockets.InitConsole();
  387.     
  388.     if (dom = SocketDomain::Domain(domain))
  389.         if (sock = dom->socket(type, protocol))
  390.             if ((fd = Sockets.Install(sock)) != -1)
  391.                 return fd;
  392.             else
  393.                 delete sock;
  394.  
  395.     if (!errno)
  396.         return GUSI_error(ENOMEM);
  397.     else
  398.         return -1;
  399. }
  400.  
  401. int socketpair(int domain, int type, int protocol, int * sv)
  402. {
  403.     SocketDomain *    dom;
  404.     Socket *         sock[2];
  405.  
  406.     Sockets.InitConsole();
  407.     
  408.     if (dom = SocketDomain::Domain(domain))
  409.         if (!dom->socketpair(type, protocol, sock))
  410.             if ((sv[0] = Sockets.Install(sock[0])) != -1)
  411.                 if ((sv[1] = Sockets.Install(sock[1])) != -1)
  412.                     return 0;
  413.                 else {
  414.                     Sockets.Remove(sv[0]);
  415.                     
  416.                     goto failInstall;
  417.                 }
  418.             else {
  419. failInstall:
  420.                 delete sock[0];
  421.                 delete sock[1];
  422.             }
  423.         
  424.     if (!errno)
  425.         return GUSI_error(ENOMEM);
  426.     else
  427.         return -1;
  428. }
  429.  
  430. int pipe(int * fd)
  431. {
  432.     GUSIwithUnixSockets();
  433.     
  434.     if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd))
  435.         return -1;
  436.     shutdown(fd[0], 1);
  437.     shutdown(fd[1], 0);
  438.     
  439.     return 0;
  440. }
  441.  
  442. int choose(int domain, int type, char * prompt, void * constraint, int flags, void * name, int * namelen)
  443. {
  444.     SocketDomain *    dom;
  445.  
  446.     if (dom = SocketDomain::Domain(domain))
  447.         return dom->choose(type, prompt, constraint, flags, name, namelen);
  448.  
  449.     return -1;
  450. }
  451.  
  452. int bind(int s, const struct sockaddr *name, int namelen)
  453. {
  454.     Socket *    sock    =    Sockets[s];
  455.  
  456.     return sock ? sock->bind((void *) name, namelen) : -1;
  457. }
  458.  
  459. int connect(int s, const struct sockaddr *addr, int addrlen)
  460. {
  461.     Socket *    sock    =    Sockets[s];
  462.  
  463.     return sock ? sock->connect((void *) addr, addrlen) : -1;
  464. }
  465.  
  466. int listen(int s, int qlen)
  467. {
  468.     Socket *    sock    =    Sockets[s];
  469.  
  470.     return sock ? sock->listen(qlen) : -1;
  471. }
  472.  
  473. int accept(int s, struct sockaddr *addr, int *addrlen)
  474. {
  475.     Socket *    sock    =    Sockets[s];
  476.  
  477.     if (sock)
  478.         if (sock    = sock->accept(addr, addrlen))
  479.             if ((s = Sockets.Install(sock)) != -1)
  480.                 return s;
  481.             else
  482.                 delete sock;
  483.  
  484.     return -1;
  485. }
  486.  
  487. int close(int s)
  488. {
  489.     errorSock    =    -1;
  490.     
  491.     return Sockets.Remove(s);
  492. }
  493.  
  494. #ifdef __MWERKS__
  495. int read(int s, char *buffer, int buflen)
  496. #else
  497. int read(int s, char *buffer, unsigned buflen)
  498. #endif
  499. {
  500.     GUSIConfig.DoAutoSpin();
  501.     
  502.     Socket *    sock    =    Sockets[s];
  503.  
  504.     return sock ? sock->read(buffer, (unsigned) buflen) : -1;
  505. }
  506.  
  507. int readv(int s, const struct iovec *iov, int count)
  508. {
  509.     GUSIConfig.DoAutoSpin();
  510.     
  511.     Socket *    sock    =    Sockets[s];
  512.  
  513.     if (sock)    {
  514.         Scatterer    scatt(iov, count);
  515.  
  516.         if (scatt)
  517.             return scatt.length(sock->read(scatt.buffer(), scatt.buflen()));
  518.         else
  519.             return GUSI_error(ENOMEM);
  520.     } else
  521.         return -1;
  522. }
  523.  
  524. int recv(int s, void *buffer, int buflen, int flags)
  525. {
  526.     GUSIConfig.DoAutoSpin();
  527.     
  528.     int         fromlen     =    0;
  529.     Socket *    sock        =    Sockets[s];
  530.  
  531.     return sock ? sock->recvfrom(buffer, buflen, flags, nil, &fromlen) : -1;
  532. }
  533.  
  534. int recvfrom(int s, void *buffer, int buflen, int flags, struct sockaddr *from, int *fromlen)
  535. {
  536.     GUSIConfig.DoAutoSpin();
  537.     
  538.     Socket *    sock    =    Sockets[s];
  539.  
  540.     return sock ? sock->recvfrom(buffer, buflen, flags, from, fromlen) : -1;
  541. }
  542.  
  543. int recvmsg(int s, struct msghdr *msg, int flags)
  544. {
  545.     GUSIConfig.DoAutoSpin();
  546.     
  547.     Socket *    sock    =    Sockets[s];
  548.  
  549.     if (sock)    {
  550.         Scatterer    scatt((struct iovec *)msg->msg_iov, msg->msg_iovlen);
  551.  
  552.         if (scatt)
  553.             return
  554.                 scatt.length(
  555.                     sock->recvfrom(
  556.                         scatt.buffer(),
  557.                         scatt.buflen(),
  558.                         flags,
  559.                         msg->msg_name,
  560.                         (int *)&msg->msg_namelen));
  561.         else
  562.             return GUSI_error(ENOMEM);
  563.     } else
  564.         return -1;
  565. }
  566.  
  567. #ifdef __MWERKS__
  568. int write(int s, const char *buffer, int buflen)
  569. #else
  570. int write(int s, const char *buffer, unsigned buflen)
  571. #endif
  572. {
  573.     /* fflush() in the MPW stdio library doesn't take no for an answer.
  574.         Our workaround is to treat a second subsequent ESHUTDOWN or EBADF as 
  575.         an invitation to lie by pretending the write worked.
  576.     */
  577.     
  578.     int    len;
  579.     
  580.     GUSIConfig.DoAutoSpin();
  581.     
  582.     Socket *    sock    =    Sockets[s];
  583.  
  584.     if (sock && (len = sock->write((char *) buffer, (unsigned) buflen)) != -1)
  585.         return len;
  586.         
  587.     switch (errno) {
  588.     case EINTR:
  589.     case EWOULDBLOCK:
  590.     case EINPROGRESS:
  591.     case EALREADY:
  592.         break;
  593.     default:
  594.         if (GUSIConfig.sigPipe)
  595.             raise(SIGPIPE);
  596.         if (errorSock == s && errorType == errno) {
  597.             if (++errorCount == errorMax) {
  598.                 errorSock = -1;
  599.             
  600.                 return buflen;
  601.             }
  602.         } else {
  603.             errorSock = s;
  604.             errorType = errno;
  605.             errorCount= 1;
  606.         }
  607.     }
  608.     return -1;
  609. }
  610.  
  611. static int HandleWriteErrors(int retval)
  612. {
  613.     if (retval == -1)
  614.         switch (errno) {
  615.         case EINTR:
  616.         case EWOULDBLOCK:
  617.         case EINPROGRESS:
  618.         case EALREADY:
  619.             break;
  620.         default:
  621.             if (GUSIConfig.sigPipe)
  622.                 raise(SIGPIPE);
  623.             break;
  624.         }
  625.     
  626.     return retval;
  627. }
  628.  
  629. int writev(int s, const struct iovec *iov, int count)
  630. {
  631.     GUSIConfig.DoAutoSpin();
  632.     
  633.     Socket *    sock    =    Sockets[s];
  634.  
  635.     if (sock)    {
  636.         Gatherer    gath(iov, count);
  637.  
  638.         if (gath)
  639.             return HandleWriteErrors(gath.length(sock->write(gath.buffer(), gath.buflen())));
  640.         else
  641.             return GUSI_error(ENOMEM);
  642.     } else
  643.         return -1;
  644. }
  645.  
  646. int send(int s, const void *buffer, int buflen, int flags)
  647. {
  648.     GUSIConfig.DoAutoSpin();
  649.     
  650.     Socket *    sock    =    Sockets[s];
  651.  
  652.     return sock ? HandleWriteErrors(sock->sendto((void *)buffer, buflen, flags, nil, 0)) : -1;
  653. }
  654.  
  655. int sendto(int s, const void *buffer, int buflen, int flags, const struct sockaddr *to, int tolen)
  656. {
  657.     GUSIConfig.DoAutoSpin();
  658.     
  659.     Socket *    sock    =    Sockets[s];
  660.  
  661.     return sock ? HandleWriteErrors(sock->sendto((void *)buffer, buflen, flags, (void *) to, tolen)) : -1;
  662. }
  663.  
  664. int sendmsg(int s, const struct msghdr *msg, int flags)
  665. {
  666.     GUSIConfig.DoAutoSpin();
  667.     
  668.     Socket *    sock    =    Sockets[s];
  669.  
  670.     if (sock)    {
  671.         Gatherer    gath((struct iovec *) msg->msg_iov, msg->msg_iovlen);
  672.  
  673.         if (gath)
  674.             return
  675.                 HandleWriteErrors(gath.length(
  676.                     sock->sendto(
  677.                         gath.buffer(),
  678.                         gath.buflen(),
  679.                         flags,
  680.                         msg->msg_name,
  681.                         msg->msg_namelen)));
  682.         else
  683.             return GUSI_error(ENOMEM);
  684.     } else
  685.         return -1;
  686. }
  687.  
  688. int select(int width, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
  689. {
  690.     Socket    *    sock;
  691.     long             count;
  692.     int             s;
  693.     long             starttime, waittime;
  694.     fd_set         rd, wd, ed;
  695.     Boolean        r,w,e;
  696.     Boolean *    canRead;
  697.     Boolean *    canWrite;
  698.     Boolean *    exception;
  699.  
  700.     count = 0;
  701.     FD_ZERO(&rd);
  702.     FD_ZERO(&wd);
  703.     FD_ZERO(&ed);
  704.  
  705.     if (timeout)
  706.         waittime =  timeout->tv_sec*60 + timeout->tv_usec/16666;
  707.     else
  708.         waittime =    2000000000;    // Slightly more than a year; close enough to "no timeout"
  709.         
  710.     starttime = LMGetTicks();
  711.  
  712.     // Check files for kosherness
  713.  
  714.     for (s = 0; s < width ; ++s)
  715.         if (    (readfds && FD_ISSET(s,readfds))
  716.             ||    (writefds && FD_ISSET(s,writefds))
  717.             ||    (exceptfds && FD_ISSET(s,exceptfds))
  718.         )
  719.             if (!Sockets[s])
  720.                 return GUSI_error(EBADF);
  721.     
  722.     for (s = 0; s < width ; ++s)
  723.         if (sock = Sockets[s]) {
  724.             r = readfds && FD_ISSET(s,readfds);
  725.             w = writefds && FD_ISSET(s,writefds);
  726.             e = exceptfds && FD_ISSET(s,exceptfds);
  727.  
  728.             if (r || w || e)
  729.                 sock->pre_select(r, w, e);
  730.         }
  731.         
  732.     do {
  733.         for (s = 0; s < width ; ++s)  {
  734.             if (sock = Sockets[s]) {
  735.                 r = false;
  736.                 w = false;
  737.                 e = false;
  738.  
  739.                 canRead = (readfds && FD_ISSET(s,readfds)) ? &r : nil;
  740.                 canWrite = (writefds && FD_ISSET(s,writefds)) ? &w : nil;
  741.                 exception = (exceptfds && FD_ISSET(s,exceptfds)) ? &e : nil;
  742.  
  743.                 if (canRead || canWrite || exception)    {
  744.                     count    += sock->select(canRead, canWrite, exception);
  745.  
  746.                     if (r)
  747.                         FD_SET(s,&rd);
  748.                     if (w)
  749.                         FD_SET(s,&wd);
  750.                     if (e)
  751.                         FD_SET(s,&ed);
  752.                 }
  753.             }
  754.         }
  755.         if (count)
  756.             break;
  757.  
  758.         SAFESPIN(false, SP_SELECT, waittime);
  759.  
  760.         if (errno) {
  761.             count = -1;
  762.             
  763.             break;
  764.         }
  765.     }  while (LMGetTicks() - starttime < waittime);
  766.  
  767.     for (s = 0; s < width ; ++s)
  768.         if (sock = Sockets[s]) {
  769.             r = readfds && FD_ISSET(s,readfds);
  770.             w = writefds && FD_ISSET(s,writefds);
  771.             e = exceptfds && FD_ISSET(s,exceptfds);
  772.  
  773.             if (r || w || e)
  774.                 sock->post_select(r, w, e);
  775.         }
  776.         
  777.     if (count < 0)
  778.         return GUSI_error(EINTR);
  779.         
  780.     if (readfds)
  781.         *readfds = rd;
  782.     if (writefds)
  783.         *writefds = wd;
  784.     if (exceptfds)
  785.         *exceptfds = ed;
  786.  
  787.     return count;
  788. }
  789.  
  790. int getsockname(int s, struct sockaddr *name, int *namelen)
  791. {
  792.     Socket *    sock    =    Sockets[s];
  793.  
  794.     return sock ? sock->getsockname(name, namelen) : -1;
  795. }
  796.  
  797. int getpeername(int s, struct sockaddr *name, int *namelen)
  798. {
  799.     Socket *    sock    =    Sockets[s];
  800.  
  801.     return sock ? sock->getpeername(name, namelen) : -1;
  802. }
  803.  
  804. int shutdown(int s, int how)
  805. {
  806.     Socket *    sock    =    Sockets[s];
  807.  
  808.     return sock ? sock->shutdown(how) : -1;
  809. }
  810.  
  811. int fcntl(int s, unsigned int cmd, int arg)
  812. {
  813.     Socket *    sock    =    Sockets[s];
  814.  
  815.     if (sock)
  816.         return (cmd == F_DUPFD) ? Sockets.Install(sock, arg) : sock->fcntl(cmd, arg);
  817.     else
  818.         return -1;
  819. }
  820.  
  821. int dup(int s)
  822. {
  823.     Socket *    sock    =    Sockets[s];
  824.  
  825.     return sock ? Sockets.Install(sock, s) : -1;
  826. }
  827.  
  828. int dup2(int s, int s1)
  829. {
  830.     Socket *    sock    =    Sockets[s];
  831.  
  832.     if (!sock)
  833.         return -1;
  834.  
  835.     if (Sockets[s1])
  836.         Sockets.Remove(s1);
  837.  
  838.     return Sockets.Install(sock, s1);
  839. }
  840.  
  841. int ioctl(int s, unsigned int request, long *argp)
  842. {
  843.     Socket *    sock    =    Sockets[s];
  844.  
  845.     if (!sock)
  846.         return -1;
  847.     
  848.     return sock->ioctl(request, argp);
  849. }
  850.  
  851. int getsockopt(int s, int level, int optname, void *optval, int * optlen)
  852. {
  853.     Socket *    sock    =    Sockets[s];
  854.  
  855.     return sock ? sock->getsockopt(level, optname, optval, optlen) : -1;
  856. }
  857.  
  858. int setsockopt(int s, int level, int optname, const void *optval, int optlen)
  859. {
  860.     Socket *    sock    =    Sockets[s];
  861.  
  862.     return sock ? sock->setsockopt(level, optname, (void *) optval, optlen) : -1;
  863. }
  864.  
  865. int fstat(int s, struct stat * buf)
  866. {
  867.     Socket *    sock    =    Sockets[s];
  868.  
  869.     return sock ? sock->fstat(buf) : -1;
  870. }
  871.  
  872. long lseek(int s, long offset, int whence)
  873. {
  874.     Socket *    sock    =    Sockets[s];
  875.  
  876.     return sock ? sock->lseek(offset, whence) : -1;
  877. }
  878.  
  879. int ftruncate(int s, long offset)
  880. {
  881.     Socket *    sock    =    Sockets[s];
  882.  
  883.     return sock ? sock->ftruncate(offset) : -1;
  884. }
  885.  
  886. int isatty(int s)
  887. {
  888.     Socket *    sock    =    Sockets[s];
  889.  
  890.     return sock ? sock->isatty() : -1;
  891. }
  892.  
  893. void GUSISetHook(GUSIHookCode code, GUSIHook hook)
  894. {
  895.     switch (code) {
  896.     case GUSI_SpinHook:
  897.         GUSISpin = (GUSISpinFn) hook;
  898.         break;
  899.     case GUSI_ExecHook:
  900.         GUSIExec = (GUSIExecFn) hook;
  901.         break;
  902.     }
  903. }
  904.  
  905. GUSIHook GUSIGetHook(GUSIHookCode code)
  906. {
  907.     switch (code) {
  908.     case GUSI_SpinHook:
  909.         return (GUSIHook) GUSISpin;
  910.     case GUSI_ExecHook:
  911.         return (GUSIHook) GUSIExec;
  912.     default:
  913.         return (GUSIHook) nil;
  914.     }
  915. }
  916.  
  917. int GUSISetEvents(GUSIEvtTable table)
  918. {
  919.     short    evt;
  920.  
  921.     evtHandler    =    table;
  922.     evtMask        =    0;
  923.  
  924.     for (evt = 0; evt<16; ++evt)
  925.         if (evtHandler[evt])
  926.             evtMask    |=    1 << evt;
  927.  
  928.     return 0;
  929. }
  930.  
  931. GUSIEvtHandler * GUSIGetEvents(void)
  932. {
  933.     return evtHandler;
  934. }
  935.  
  936. /*********************** SocketDomain members ***********************/
  937.  
  938. #ifndef GUSI_DISPATCH
  939.  
  940. SocketDomain *            SocketDomain::domains[GUSI_MAX_DOMAIN];
  941. ProcessSerialNumber    SocketDomain::process;
  942.  
  943. SocketDomain * SocketDomain::Domain(int domain)
  944. {
  945.     if (domain < 0 || domain >= GUSI_MAX_DOMAIN || !domains[domain])    {
  946.         GUSI_error(EINVAL);
  947.  
  948.         return nil;
  949.     } else
  950.         return domains[domain];
  951. }
  952.  
  953. void SocketDomain::Ready()
  954. {
  955.     if (hasProcessMgr)
  956.         WakeUpProcess(&process);
  957. }
  958.  
  959. SocketDomain::SocketDomain(int domain)
  960. {
  961. #ifdef PREVENT_DUPLICATE_DOMAINS
  962.     if (domains[domain])    {
  963.         Str63    msg;
  964.  
  965.         sprintf((char *) msg+1, "Duplicate declaration for domain %d\n", domain);
  966.         msg[0] = (unsigned char)strlen((char *) msg+1);
  967.  
  968.         DebugStr(msg);
  969.     }
  970. #endif
  971.     if (domain)                                    // Ignore AF_UNSPEC domains
  972.         domains[domain]    =    this;
  973.     
  974.     if (hasProcessMgr && !process.highLongOfPSN && !process.lowLongOfPSN)
  975.         GetCurrentProcess(&process);
  976. }
  977.  
  978. SocketDomain::~SocketDomain()
  979. {
  980. }
  981.  
  982. // Default implementations of socket() just returns an error
  983.  
  984. Socket * SocketDomain::socket(int, short)
  985. {
  986.     GUSI_error(EOPNOTSUPP);
  987.  
  988.     return nil;
  989. }
  990.  
  991. // Same with socketpair
  992.  
  993. int SocketDomain::socketpair(int, short, Socket **)
  994. {
  995.     return GUSI_error(EOPNOTSUPP);
  996. }
  997.  
  998.  
  999. int SocketDomain::choose(int, char *, void *, int, void *, int *)
  1000. {
  1001.     return GUSI_error(EOPNOTSUPP);
  1002. }
  1003.  
  1004. void SocketDomain::DontStrip()
  1005. {
  1006. }
  1007.  
  1008. /*********************** SocketTable members ************************/
  1009.  
  1010. static void FlushStdio()
  1011. {
  1012.     fwalk(fflush);
  1013. }
  1014.  
  1015. SocketTable::SocketTable()
  1016. {
  1017.     atexit(FlushStdio);
  1018.     
  1019.     needsConsole = true;
  1020. }
  1021.     
  1022. int SocketTable::Install(Socket * sock, int start)
  1023. {
  1024.     short    fd;
  1025.  
  1026.     if (start<0 || start >= GUSI_MAX_FD)
  1027.         return GUSI_error(EINVAL);
  1028.  
  1029.     for (fd=start; fd<GUSI_MAX_FD; ++fd)
  1030.         if (!sockets[fd])    {
  1031.             sockets[fd] = sock;
  1032.         
  1033.             ++sock->refCount;
  1034.             return fd;
  1035.         }
  1036.  
  1037.     return GUSI_error(EMFILE);
  1038. }
  1039.  
  1040. int SocketTable::Remove(int fd)
  1041. {
  1042.     Socket *    sock;
  1043.  
  1044.     InitConsole();
  1045.  
  1046.     if (fd<0 || fd >= GUSI_MAX_FD || !(sock = sockets[fd]))
  1047.         return GUSI_error(EBADF);
  1048.  
  1049.     sockets[fd]     =    nil;
  1050.  
  1051.     if (!--sock->refCount)
  1052.         delete sock;
  1053.  
  1054.     return 0;
  1055. }
  1056.  
  1057. Socket * SocketTable::operator[](int fd)
  1058. {
  1059.     Socket * sock;
  1060.  
  1061.     InitConsole();
  1062.     
  1063.     if (fd<0 || fd >= GUSI_MAX_FD || !(sock = sockets[fd]))    {
  1064.         GUSI_error(EBADF);
  1065.  
  1066.         return nil;
  1067.     } else
  1068.         return sock;
  1069. }
  1070.  
  1071. #ifndef powerc
  1072. #pragma far_code
  1073. #endif
  1074.  
  1075. SocketTable::~SocketTable()
  1076. {
  1077.     int i;
  1078.  
  1079.     // Flush stdio files (necessary to flush buffers)
  1080.  
  1081.     fwalk(fflush);
  1082.  
  1083.     // If we didn't need a console so far, we certainly don't need one now!
  1084.     // Doing this further up would be dangerous for small write only apps
  1085.     
  1086.     needsConsole = false;
  1087.  
  1088.     // Now close stdio files, just to be sure
  1089.  
  1090.     fwalk(fclose);
  1091.  
  1092.     // Close all files
  1093.  
  1094.     for (i = 0; i<GUSI_MAX_FD; ++i)
  1095.         if (sockets[i])
  1096.             close(i);
  1097. }
  1098.  
  1099. #ifndef powerc
  1100. #pragma smart_code
  1101. #endif
  1102.  
  1103. /********************** sleep()/alarm() ***********************/
  1104.  
  1105. static long    GUSIAlarm = 0;
  1106.  
  1107. int GUSICheckAlarm()
  1108. {
  1109.     if (GUSIAlarm && LMGetTicks() > GUSIAlarm) {
  1110.         GUSIAlarm = 0;
  1111.         raise(SIGALRM);
  1112.         
  1113.         return 1;
  1114.     } else
  1115.         return 0;
  1116. }
  1117.  
  1118. u_int     alarm(u_int seconds)
  1119. {
  1120.     long remaining = GUSIAlarm ? (LMGetTicks() - GUSIAlarm) / 60 : 0;
  1121.     
  1122.     GUSIAlarm = seconds ? LMGetTicks() + 60 * seconds : 0;
  1123.     
  1124.     return (remaining < 0) ? 0 : (u_int) remaining;
  1125. }
  1126.  
  1127. static u_int DoSleep(long ticks)
  1128. {
  1129.     long wakeup = LMGetTicks() + ticks;
  1130.     
  1131.     SAFESPIN(wakeup > LMGetTicks(), SP_SLEEP, wakeup - LMGetTicks());
  1132.     
  1133.     long remaining = (LMGetTicks() - wakeup) / 60;
  1134.     
  1135.     return (remaining < 0) ? 0 : (u_int) remaining;
  1136. }
  1137.  
  1138. u_int sleep(u_int seconds) 
  1139. {
  1140.     return DoSleep(seconds * 60);
  1141. }
  1142.  
  1143. void usleep(u_int useconds)
  1144. {
  1145.     DoSleep((useconds * 3) / 50000);
  1146. }
  1147.  
  1148. /********************** Default spin function ***********************/
  1149.  
  1150. /* Borrowed from tech note 263 */
  1151.  
  1152. #define kMaskModifiers      0xFE00         // we need the modifiers without the
  1153.                                            // command key for KeyTrans
  1154. #define kMaskVirtualKey     0x0000FF00     // get virtual key from event message
  1155.                                            // for KeyTrans
  1156. #define kUpKeyMask          0x0080
  1157. #define kShiftWord          8              // we shift the virtual key to mask it
  1158.                                            // into the keyCode for KeyTrans
  1159. #define kMaskASCII1         0x00FF0000     // get the key out of the ASCII1 byte
  1160. #define kMaskASCII2         0x000000FF     // get the key out of the ASCII2 byte
  1161. #define kPeriod             0x2E           // ascii for a period
  1162.  
  1163. static Boolean CmdPeriod(EventRecord *theEvent)
  1164. {
  1165.       Boolean  fTimeToQuit;
  1166.       short    keyCode;
  1167.       long     virtualKey, keyInfo, lowChar, highChar, keyCId;
  1168.       UInt32    state;
  1169.       Handle   hKCHR;
  1170.     Ptr         KCHRPtr;
  1171.  
  1172.     fTimeToQuit = false;
  1173.  
  1174.     if (((*theEvent).what == keyDown) || ((*theEvent).what == autoKey)) {
  1175.  
  1176.         // see if the command key is down.  If it is, find out the ASCII
  1177.         // equivalent for the accompanying key.
  1178.  
  1179.         if ((*theEvent).modifiers & cmdKey ) {
  1180.  
  1181.             virtualKey = ((*theEvent).message & kMaskVirtualKey) >> kShiftWord;
  1182.             // And out the command key and Or in the virtualKey
  1183.             keyCode    = short(((*theEvent).modifiers & kMaskModifiers) | virtualKey);
  1184.             state      = 0;
  1185.  
  1186.             hKCHR = nil;  /* set this to nil before starting */
  1187.              KCHRPtr = (Ptr)GetEnvirons(smKCHRCache);
  1188.  
  1189.             if ( !KCHRPtr ) {
  1190.                 keyCId = GetScript(short(GetEnvirons(smKeyScript)), smScriptKeys);
  1191.  
  1192.                 hKCHR   = GetResource('KCHR',short(keyCId));
  1193.                 KCHRPtr = *hKCHR;
  1194.             }
  1195.  
  1196.             if (KCHRPtr) {
  1197.                 keyInfo = KeyTrans(KCHRPtr, keyCode, &state);
  1198.                 if (hKCHR)
  1199.                     ReleaseResource(hKCHR);
  1200.             } else
  1201.                 keyInfo = (*theEvent).message;
  1202.  
  1203.             lowChar =  keyInfo &  kMaskASCII2;
  1204.             highChar = (keyInfo & kMaskASCII1) >> 16;
  1205.             if (lowChar == kPeriod || highChar == kPeriod)
  1206.                 fTimeToQuit = true;
  1207.  
  1208.         }  // end the command key is down
  1209.     }  // end key down event
  1210.  
  1211.     return( fTimeToQuit );
  1212. }
  1213.  
  1214. Boolean GUSIInterrupt()
  1215. {
  1216.     EvQElPtr        eventQ;
  1217.  
  1218.     for (eventQ = (EvQElPtr) LMGetEventQueue()->qHead; eventQ; )
  1219.         if (CmdPeriod((EventRecord *) &eventQ->evtQWhat))
  1220.             return true;
  1221.         else
  1222.             eventQ = (EvQElPtr)eventQ->qLink;
  1223.     
  1224.     return false;
  1225. }
  1226.  
  1227. int StandAlone = 1;
  1228.  
  1229. int GUSIDefaultSpin(spin_msg msg, long arg)
  1230. {
  1231.     static Boolean            inForeground    =    true;
  1232.     WindowPtr                win;
  1233.     EventRecord                ev;
  1234.     long                        sleepTime         =    6;    // 1/10 of a second by default
  1235.  
  1236.     GUSIConfig.AutoInitGraf();
  1237.     
  1238.     if (inForeground)
  1239.         SpinCursor(msg == SP_AUTO_SPIN ? short(arg) : 1);
  1240.  
  1241.     if (GUSIInterrupt())
  1242.         goto interrupt;
  1243.  
  1244.     if (!StandAlone && inForeground)
  1245.         return 0;                                // For MPW tools, SpinCursor already calls WNE
  1246.         
  1247.     switch (msg) {
  1248.     case SP_SLEEP:
  1249.     case SP_SELECT:
  1250.         if (arg >= sleepTime)                // Only sleep if patience guaranteed
  1251.             break;
  1252.         // Otherwise, fall through    
  1253.     case SP_AUTO_SPIN:
  1254.         sleepTime = 0;
  1255.         break;
  1256.     default:
  1257.         break;
  1258.     }
  1259.     
  1260.     if (WaitNextEvent(osMask|highLevelEventMask|mDownMask|evtMask, &ev, sleepTime, nil))
  1261.         switch (ev.what) {
  1262.         case mouseDown:
  1263.             if (!evtHandler || !evtHandler[mouseDown])
  1264.                 if (FindWindow(ev.where, &win) == inSysWindow)
  1265.                     SystemClick(&ev, win);
  1266.  
  1267.             break;
  1268.         case osEvt:
  1269.             if (ev.message & 1)
  1270.                 inForeground    =    true;
  1271.             else
  1272.                 inForeground    =    false;
  1273.             break;
  1274.         case kHighLevelEvent:
  1275.             if (!evtHandler || !evtHandler[kHighLevelEvent])
  1276.                 if (hasAppleEvents)                // actually pretty likely, if we get HL Events
  1277.                     AEProcessAppleEvent(&ev);    // Ignore errors
  1278.             break;
  1279.         default:
  1280.             break;
  1281.         }
  1282.  
  1283.     if (ev.what >= 0 && ev.what < 24 && evtHandler && evtHandler[ev.what])
  1284.         evtHandler[ev.what](&ev);
  1285.  
  1286.     return 0;
  1287.  
  1288. interrupt:
  1289.     FlushEvents(-1, 0);
  1290.  
  1291.     return -1;
  1292. }
  1293.  
  1294. /************************** Feature members **************************/
  1295.  
  1296. Feature::Feature(unsigned short trapNum, TrapType tTyp)
  1297. {
  1298.     good =
  1299.         NGetTrapAddress(trapNum, tTyp) != NGetTrapAddress(_Unimplemented, ToolTrap);
  1300. }
  1301.  
  1302. Feature::Feature(OSType type, long value)
  1303. {
  1304.     long        attr;
  1305.  
  1306.     good = (!Gestalt(type, &attr) && (attr >= value));
  1307. }
  1308.  
  1309. Feature::Feature(OSType type, long mask, long value)
  1310. {
  1311.     long        attr;
  1312.  
  1313.     good = (!Gestalt(type, &attr) && ((attr & mask) == value));
  1314. }
  1315.  
  1316. Feature::Feature(const Feature & precondition, OSErrInitializer init)
  1317. {
  1318.     good    =    precondition && !init();
  1319. }
  1320.  
  1321. Feature::Feature(OSErrInitializer init)
  1322. {
  1323.     good    =    !init();
  1324. }
  1325.  
  1326. Feature::Feature(const Feature & precondition, voidInitializer init)
  1327. {
  1328.     if (precondition)    {
  1329.         good = true;
  1330.         init();
  1331.     } else
  1332.         good = false;
  1333. }
  1334.  
  1335. Feature::Feature(voidInitializer init)
  1336. {
  1337.     good = true;
  1338.     init();
  1339. }
  1340.  
  1341. Feature::Feature(const Feature & cond1, const Feature & cond2)
  1342. {
  1343.     good = cond1 && cond2;
  1344. }
  1345.  
  1346. OSErr AppleTalkIdentity(short & net, short & node)
  1347. {
  1348.     static short    mynet;
  1349.     static short    mynode;
  1350.     static OSErr    err = 1;
  1351.  
  1352.     if (err == 1)
  1353.         if (!(err = MPPOpen()))
  1354.             err = GetNodeAddress(&mynode, &mynet);
  1355.  
  1356.  
  1357.     net    =    mynet;
  1358.     node    =    mynode;
  1359.  
  1360.     return err;
  1361. }
  1362.  
  1363. /************************** Setup suppport **************************/
  1364.  
  1365. /* Pray that the following function never inlines GUSISetup */
  1366.  
  1367. void GUSIDefaultSetup()
  1368. {
  1369.     GUSISetup(GUSIwithAppleTalkSockets);
  1370.     GUSISetup(GUSIwithInternetSockets);
  1371.     GUSISetup(GUSIwithPAPSockets);
  1372.     GUSISetup(GUSIwithPPCSockets);
  1373.     GUSISetup(GUSIwithUnixSockets);
  1374.     GUSISetup(GUSIwithSIOUXSockets);
  1375. }
  1376.  
  1377. void GUSISetup(void (*proc)())
  1378. {
  1379.     proc();
  1380. }
  1381.  
  1382. void GUSILoadConfiguration(Handle hdl)
  1383. {
  1384.     GUSIConfig.GUSILoadConfiguration(hdl);
  1385. }
  1386.  
  1387. #endif // GUSI_DISPATCH
  1388.